using Tyng.Web.UI.Script;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Web.UI;

namespace Tyng.Web.UI.YUI
{
    public class Tree : Control, IPostBackEventHandler
    {
        public Tree()
        {
            _nodes = new TreeNodeCollection(this);
        }

        #region Properties
        TreeNodeCollection _nodes;

        public TreeNodeCollection Nodes
        {
            get
            {
                return _nodes;
            }
        }

        [DefaultValue("")]
        public string SelectedCssClass
        {
            get
            {
                string s = (string)ViewState["SelectedCssClass"];

                if (string.IsNullOrEmpty(s)) return string.Empty;

                return s;
            }
            set
            {
                ViewState["SelectedCssClass"] = value;
            }
        }

        [DefaultValue("")]
        public string SelectedValue
        {
            get
            {
                string s = (string)ViewState["SelectedValue"];

                if (string.IsNullOrEmpty(s)) return string.Empty;

                return s;
            }
            set
            {
                ViewState["SelectedValue"] = value;
            }
        }

        #endregion

        #region ViewState
        protected override void TrackViewState()
        {
            base.TrackViewState();

            ((IStateManager)_nodes).TrackViewState();
        }

        protected override void LoadViewState(object savedState)
        {
            if (savedState != null)
            {
                Pair p = (Pair)savedState;

                base.LoadViewState(p.First);
                ((IStateManager)_nodes).LoadViewState(p.Second);
            }
        }

        protected override object SaveViewState()
        {
            Pair p = new Pair(
                base.SaveViewState(), 
                ((IStateManager)_nodes).SaveViewState());

            return p;
        }
        #endregion

        protected override ControlCollection CreateControlCollection()
        {
            return new EmptyControlCollection(this);
        }

        protected override void Render(HtmlTextWriter writer)
        {
            string divId = this.ClientID + "_target";
            string functionName = "treeInit_" + this.ClientID;

            writer.AddAttribute(HtmlTextWriterAttribute.Id, divId);
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            writer.RenderEndTag();

            writer.AddAttribute(HtmlTextWriterAttribute.Type, "text/javascript");
            writer.RenderBeginTag(HtmlTextWriterTag.Script);

            writer.Write("function ");
            writer.Write(functionName);
            writer.Write("(){var tree=new YAHOO.widget.TreeView(");
            writer.Write(divId);
            writer.Write(");var root=tree.getRoot();");

            _nodes.Render(writer, "root");

            writer.Write("tree.subscribe('labelClick', function(node){node.postBack();});");

            writer.Write("tree.draw();}");
            writer.WriteLine("YAHOO.util.Event.addListener(window, 'load', " + functionName + ");");
            writer.RenderEndTag();
        }

        public event EventHandler NodeSelected;

        protected virtual void OnNodeSelected(EventArgs args)
        {
            if (NodeSelected != null)
                NodeSelected(this, args);
        }

        #region IPostBackEventHandler Members

        void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
        {
            this.SelectedValue = eventArgument;
            OnNodeSelected(EventArgs.Empty);
        }

        #endregion
    }

    public class TreeNode : IStateManager
    {
        public TreeNode() { }

        public TreeNode(string content)
        {
            this.Content = content;
        }

        public TreeNode(string content, string cssClass)
        {
            this.Content = content;
            this.CssClass = cssClass;
        }

        protected internal virtual void Render(HtmlTextWriter writer, string parentNode, string varUnique)
        {
            string var = parentNode + "_" + varUnique;

            writer.Write("var " + var + " = new YAHOO.widget.");

        
            writer.Write("TextNode({label:");
            writer.Write(JavaScript.ToString(Content));
            writer.Write(",href:'#',labelStyle:");
            writer.Write(JavaScript.ToString(CssClass));
            writer.Write("},");
            writer.Write(parentNode);
            writer.Write(",");
            writer.Write(JavaScript.ToString(Expanded));
            writer.Write(");");

            PostBackOptions pbo = new PostBackOptions(Tree, this.Value);
            pbo.ClientSubmit = true;
            pbo.AutoPostBack = true;
            pbo.PerformValidation = false;

            writer.Write(var + ".postBack=function(){" + Tree.Page.ClientScript.GetPostBackEventReference(pbo) + ";};");

            _children.Render(writer, var);
        }

        Tree _tree;

        public Tree Tree { get { return _tree; } }

        internal void SetTree(Tree t)
        {
            _tree = t;
            _children.SetTree(t);
        }

        #region Properties
        bool _isTrackingViewState;
        StateBag _viewState;
        TreeNodeCollection _children = new TreeNodeCollection();

        public TreeNodeCollection Children
        {
            get
            {
                return _children;
            }
        }

        [DefaultValue(false)]
        public bool Expanded
        {
            get
            {
                object o = ViewState["Expanded"];

                if (o != null) return (bool)o;

                return false;
            }
            set
            {
                ViewState["Expanded"] = value;
            }
        }

        [DefaultValue(true)]
        public bool HasIcon
        {
            get
            {
                object o = ViewState["HasIcon"];

                if (o != null) return (bool)o;

                return true;
            }
            set
            {
                ViewState["HasIcon"] = value;
            }
        }

        [DefaultValue(true)]
        public bool NoWrap
        {
            get
            {
                object o = ViewState["NoWrap"];

                if (o != null) return (bool)o;

                return true;
            }
            set
            {
                ViewState["NoWrap"] = value;
            }
        }

        [DefaultValue("")]
        public string Value
        {
            get
            {
                string s = (string)ViewState["Value"];

                if (string.IsNullOrEmpty(s)) return string.Empty;

                return s;
            }
            set
            {
                ViewState["Value"] = value;
            }
        }

        [DefaultValue("")]
        public string Content
        {
            get
            {
                string s = (string)ViewState["Content"];

                if (string.IsNullOrEmpty(s)) return string.Empty;

                return s;
            }
            set
            {
                ViewState["Content"] = value;
            }
        }

        const string DefaultCssClass = "ygtvlabel";

        [DefaultValue(DefaultCssClass)]
        public string CssClass
        {
            get
            {
                string s = (string)ViewState["CssClass"];

                if (string.IsNullOrEmpty(s)) return DefaultCssClass;

                return s;
            }
            set
            {
                ViewState["CssClass"] = value;
            }
        }

        #endregion

        #region ViewState
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Browsable(false)]
        protected StateBag ViewState
        {
            get
            {
                if (this._viewState == null)
                {
                    this._viewState = new StateBag(false);
                    if (this._isTrackingViewState)
                    {
                        ((IStateManager)this._viewState).TrackViewState();
                    }
                }
                return this._viewState;
            }
        }

        protected virtual void LoadViewState(object savedState)
        {
            if (savedState != null)
            {
                Pair p = (Pair)savedState;

                ((IStateManager)ViewState).LoadViewState(p.First);

                if (p.Second != null)
                {
                    ((IStateManager)_children).LoadViewState(p.Second);
                }
            }
        }

        protected virtual object SaveViewState()
        {
            Pair p = new Pair();

            if (this._viewState != null)
            {
                p.First = ((IStateManager)_viewState).SaveViewState();
            }

            p.Second = ((IStateManager)_children).SaveViewState();

            return p;
        }

        protected virtual void TrackViewState()
        {
            this._isTrackingViewState = true;
            if (this._viewState != null)
            {
                ((IStateManager)_viewState).TrackViewState();
            }

            ((IStateManager)_children).TrackViewState();
        }

        protected virtual bool IsTrackingViewState
        {
            get
            {
                return this._isTrackingViewState;
            }
        }

        protected internal void SetDirty()
        {
            if (this._viewState != null)
                this._viewState.SetDirty(true);

            _children.SetDirty();
        }
        #endregion

        #region IStateManager Members

        bool IStateManager.IsTrackingViewState
        {
            get { return this.IsTrackingViewState; }
        }

        void IStateManager.LoadViewState(object state)
        {
            this.LoadViewState(state);
        }

        object IStateManager.SaveViewState()
        {
            return this.SaveViewState();
        }

        void IStateManager.TrackViewState()
        {
            this.TrackViewState();
        }

        #endregion
    }

    public class TreeNodeCollection : StateManagedCollection
    {
        public TreeNodeCollection()
        {
        }

        public TreeNodeCollection(Tree t)
        {
            _tree = t;
        }

        Tree _tree;

        protected Tree Tree { get { return _tree; } }

        internal void SetTree(Tree t)
        {
            _tree = t;

            foreach (TreeNode n in this)
                n.SetTree(t);
        }

        public void ExpandAll()
        {
            foreach (TreeNode n in this)
            {
                n.Expanded = true;
                n.Children.ExpandAll();
            }
        }

        protected internal virtual void Render(HtmlTextWriter writer, string parentNode)
        {
            for (int i = 0; i < this.Count; i++)
            {
                this[i].Render(writer, parentNode, i.ToString());
            }
        }

        public int Add(TreeNode mi)
        {
            return ((IList)this).Add(mi);
        }

        protected override void OnInsertComplete(int index, object value)
        {
            base.OnInsertComplete(index, value);

            ((TreeNode)value).SetTree(_tree);
        }

        protected override void OnRemoveComplete(int index, object value)
        {
            base.OnRemoveComplete(index, value);

            ((TreeNode)value).SetTree(null);
        }

        public void AddRange(IEnumerable<TreeNode> menuItems)
        {
            foreach (TreeNode mi in menuItems)
                Add(mi);
        }

        protected override void SetDirtyObject(object o)
        {
            ((TreeNode)o).SetDirty();
        }

        public TreeNode this[int index]
        {
            get
            {
                return (TreeNode)((IList)this)[index];
            }
        }
    }
}
